home *** CD-ROM | disk | FTP | other *** search
Text File | 2007-10-18 | 32.2 KB | 1,006 lines |
- // BEGIN FLOCK GPL
- //
- // Copyright Flock Inc. 2005-2007
- // http://flock.com
- //
- // This file may be used under the terms of of the
- // GNU General Public License Version 2 or later (the "GPL"),
- // http://www.gnu.org/licenses/gpl.html
- //
- // Software distributed under the License is distributed on an "AS IS" basis,
- // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- // for the specific language governing rights and limitations under the
- // License.
- //
- // END FLOCK GPL
-
- const CC = Components.classes;
- const CI = Components.interfaces;
- const CR = Components.results;
-
- Components.utils.import("resource:///modules/FlockXPCOMUtils.jsm");
- FlockXPCOMUtils.debug = false;
-
- const MODULE_NAME = "Flock Rich Drag and Drop Service";
-
- // The Rich Drag&Drop service
- const FLOCK_RICHDRAGDROP_SERVICE_CLASS_NAME
- = "Flock Rich Drag and Drop Service";
- const FLOCK_RICHDRAGDROP_SERVICE_CLASS_ID
- = Components.ID("{30b8dc92-abe0-44ee-a845-e1a827d59610}");
- const FLOCK_RICHDRAGDROP_SERVICE_CONTRACT_ID = "@flock.com/rich-dnd-service;1";
- const FLOCK_PREF_SERVICE_CONTRACT_ID = "@mozilla.org/preferences-service;1";
- const FLOCK_CATEGORY_MANAGER_CONTRACT_ID = "@mozilla.org/categorymanager;1";
- const FLOCK_RICH_CONTENT_CATEGORY_ENTRY = "flockRichContentHandler";
- const FLOCK_BREADCRUMB_ID = "flock-breadcrumb";
-
- const FLAVOR_UNICODE = "text/unicode";
- const FLAVOR_HTML = "text/html";
- const FLAVOR_MOZ_URL = "text/x-moz-url";
- const FLAVOR_FLOCK_MEDIA = "text/x-flock-media";
- const FLAVOR_TEXT_CITE = "text/x-flock-textcitation";
- const FLAVOR_HTML_CITE = "text/x-flock-htmlcitation";
- const FLAVOR_MOZ_RDF = "moz/rdfitem";
-
- // From viewPartialSource.js
- //
- // These are markers used to delimit the selection during processing. They
- // are removed from the final rendering, but we pick space-like characters for
- // safety (and futhermore, these are known to be mapped to a 0-length string
- // in transliterate.properties). It is okay to set start=end, we use findNext()
- // U+200B ZERO WIDTH SPACE
- const MARK_SELECTION_START = "\u200B\u200B\u200B\u200B\u200B";
- const MARK_SELECTION_END = "\u200B\u200B\u200B\u200B\u200B";
-
- const NS_XHTML = "http://www.w3.org/1999/xhtml";
-
- var _logger = CC["@flock.com/logger;1"].createInstance(CI.flockILogger);
- _logger.init("flockRichDragDropService");
-
- /**************************************************************************
- * Component: Flock Rich Drag and Drop Service
- **************************************************************************/
-
- // Constructor.
- function flockRichDragDropService() {
- }
-
- /**************************************************************************
- * Flock Rich Drag and Drop Service: XPCOM Component Creation
- **************************************************************************/
-
- flockRichDragDropService.prototype = new FlockXPCOMUtils.genericComponent(
- FLOCK_RICHDRAGDROP_SERVICE_CLASS_NAME,
- FLOCK_RICHDRAGDROP_SERVICE_CLASS_ID,
- FLOCK_RICHDRAGDROP_SERVICE_CONTRACT_ID,
- flockRichDragDropService,
- CI.nsIClassInfo.SINGLETON,
- [
- CI.flockIRichDNDService
- ]
- );
-
- // FlockXPCOMUtils.genericComponent() registration callbacks.
- flockRichDragDropService.prototype.register =
- function flockRichDragDropService_register(aCompMgr, aFileSpec, aLocation, aType) {
- }
-
- flockRichDragDropService.prototype.unregister =
- function flockRichDragDropService_unregister(aCompMgr, aFileSpec, aLocation, aType) {
- }
-
- /**************************************************************************
- * Flock Rich Drag and Drop Service: flockIRichDNDService Implementation
- **************************************************************************/
-
- flockRichDragDropService.prototype.getRichSelection =
- function fRDDS_getRichSelection(aSession) {
- var node = aSession.sourceNode;
- // Dragging from outside the browser
- if (!node) {
- return null;
- }
-
- // Gather some information about the current window, as it can be used
- // to enrich the data we will be sending
- var wm = CC["@mozilla.org/appshell/window-mediator;1"]
- .getService(CI.nsIWindowMediator);
- var top = wm.getMostRecentWindow("navigator:browser");
- var contentElement = top.document.getElementById("content");
- var topUrl = contentElement.contentDocument.URL;
- var topTitle = contentElement.contentTitle;
- if (topTitle.length == 0) {
- topTitle = contentElement.contentDocument.location;
- }
- if (topUrl && topUrl.match(/^chrome:\/\/.+/)) {
- // Never mark content with a chrome URL, as it is likely to be send
- // to someone or published online
- topUrl = "";
- }
-
- var nodeName = node.nodeName.toLowerCase();
- _logger.debug("nodeName="+nodeName);
-
- // HTML image from a web page
- if (nodeName == "img") {
- var imageTitle = "";
- if (node.title) {
- imageTitle = node.title;
- } else if (node.alt) {
- imageTitle = node.alt;
- }
- var imageURL = this._makeURLAbsolute(topUrl, node.src);
- // Don't insert a stupid image containing Javascript
- if (imageURL.match("javascript:")) {
- return null;
- }
- if (imageURL == topUrl) {
- // Bug 3756, when the image alone is displayed in the browser
- // Mozilla is replacing the "alt" tag by "This image contains error"
- // a clever hack, but we don't want to use that for the title
- imageTitle = imageURL.split("/").pop();
- }
-
- return this._getImageTransferable(imageURL, imageTitle, topUrl);
- }
-
- // The URL bar favicon: appear as a XUL image but must be treated as a link
- if ((nodeName == "image") || (nodeName == "xul:image")) {
- return this._getLinkTransferable(topUrl, topTitle);
- }
-
- // Browser tab: to be sent as a link
- if ((nodeName == "tab") || (nodeName == "xul:tab")) {
- var tabUrl = top.content.document.location.toString();
- var tabTitle = node.label;
-
- return this._getLinkTransferable(tabUrl, tabTitle);
- }
-
- // Mediabar
- if ((nodeName == "photo") || (nodeName == "xul:photo")) {
- return this._getMediabarTransferable(node, topUrl);
- }
-
- // Do not support these
- if ((nodeName == "shelficon") || (nodeName == "richtreefolder")) {
- return null;
- }
-
- // Deal with a selection
- var selection = top.getSelection();
-
- if (selection.toString().length > 0) {
- return this._getSelectionTransferable(topUrl, topTitle, selection);
- }
-
- // If we don't find a SRC or HREF tag in this node, then it is most likely an
- // inline element, so we will traverse through its ancestors until we find
- // something we can use.
- while (node && node != contentElement.contentDocument.body) {
- if (node.src) {
- // If it is an img, make sure the src attribute is the full path
- node.setAttribute("src", node.src);
- var imageURL = node.src;
- var imageTitle = node.src;
- if (node.getAttribute("title")) {
- imageTitle = node.getAttribute("title");
- } else if (node.getAttribute("alt")) {
- imageTitle = node.getAttribute("alt");
- }
- return this._getImageTransferable(imageURL, imageTitle, topUrl);
- }
-
- if (node.href) {
- // If it is a link make sure the href attribute is the full path
- node.setAttribute("href", node.href);
- return this._getLinkTransferable(node.href, node.textContent);
- }
-
- // Look at parent
- node = node.parentNode;
- }
-
- // Don't know... we can return a link to the page
- return this._getLinkTransferable(topUrl, topTitle);
- }
-
-
- flockRichDragDropService.prototype.getMessageFromTransferable =
- function fRDDS_getMessageFromTransferable(aSubject, aListSize, aFlavorList)
- {
- var message = {};
-
- // Get transferable's available flavors
- var transFlavors = aSubject.flavorsTransferableCanExport();
- // Build string array of flavors for easy compare
- var transFlavorArray = [];
- for (var i = 0; i < transFlavors.Count(); i++) {
- transFlavorArray[i] = transFlavors.GetElementAt(i)
- .QueryInterface(CI.nsISupportsCString)
- .data;
- }
-
- // Go through list of desired flavors
- for (var i = 0; i < aListSize; i++) {
- // Is this flavor available in the transferable?
- var flavor = aFlavorList[i];
- if (transFlavorArray.indexOf(flavor) != -1) {
- // It is -- try to build a message using it
- message = this._getMessageFromTransferableWithFlavor(aSubject, flavor);
- if (message.body) {
- // Successfully built a message from this transferable
- return message;
- }
- }
- }
-
- // None of the desired flavors are available in the transferable. If it has a
- // flavor we support, use it instead.
- for (var i = 0; i < transFlavorArray.length; i++) {
- // Get a flavor from the transferable
- var flavor = transFlavorArray[i];
- // Try to build a message using it
- message = this._getMessageFromTransferableWithFlavor(aSubject, flavor);
- if (message.body) {
- // Successfully built a message from this transferable
- return message;
- }
- }
-
- // No valid flavor available
- _logger.debug("Could not find a supported flavor.");
-
- // We should do something to support it
- throw "No Supported Flavour for Sharing";
- }
-
-
- flockRichDragDropService.prototype.getBreadcrumb =
- function fRDDS_getBreadcrumb(aType)
- {
- var breadcrumb = "";
-
- // Is breadcrumb enabled?
- var prefService = CC[FLOCK_PREF_SERVICE_CONTRACT_ID]
- .getService(CI.nsIPrefBranch);
-
- if (prefService.getPrefType("flock.sharing.breadcrumb.enabled")
- && prefService.getBoolPref("flock.sharing.breadcrumb.enabled"))
- {
- var footer = flockGetString("common/sharing", "flock.sharing.breadcrumb.footer1");
- var url = flockGetString("common/sharing", "flock.sharing.breadcrumb.url");
-
- // Build breadrcumb based on desired type of formatting
- if (aType == "rich") {
- breadcrumb = "<br /><br />" + footer + "<br />"
- + "<a href='" +url + "'>" + url + "</a>" + "<br />";
- } else {
- // aType == "plain"
- breadcrumb = "\n\n" + footer + "\n" + url + "\n";
- }
- }
-
- return breadcrumb;
- }
-
-
- flockRichDragDropService.prototype.handleDrop =
- function frDDS_handleDrop(aSession, aTargetElement) {
- var type = aTargetElement.localName.toLowerCase();
-
- if (type == "textarea") {
- if (this._handleDropToTextArea(aSession, aTargetElement)) {
- return true;
- }
- } else if (this._isInRichTextEditor(aTargetElement)) {
- if (this._handleDropToRichTextEditor(aSession, aTargetElement)) {
- return true;
- }
- }
-
- // Not handled - do something else?
- return false;
- }
-
- /**************************************************************************
- * Flock Rich Drag Drop Service Private Members
- **************************************************************************/
-
- flockRichDragDropService.prototype._getMessageFromTransferableWithFlavor =
- function fRDDS_getMessageFromTransferableWithFlavor(aSubject, aFlavor) {
- var message = {};
- message.QueryInterface = function (aIID) {
- if (aIID.equals(CI.flockIMessage) || aIID.equals(CI.nsISupports)) {
- return this;
- }
- throw CR.NS_ERROR_NO_INTERFACE;
- };
-
- // Get content from transferable
- var content = this._getFlavourData(aSubject, aFlavor);
- if (!content) {
- return message;
- }
-
- // Build message from content
- var contentParts;
- switch (aFlavor) {
- case FLAVOR_MOZ_RDF:
- var coop = CC["@flock.com/singleton;1"]
- .getService(CI.flockISingleton)
- .getSingleton("chrome://flock/content/common/load-faves-coop.js")
- .wrappedJSObject;
- var item = coop.get(content);
- message.subject = item.name;
- if (item.isInstanceOf(coop.FeedItem)) {
- message.body = this._getFlavourData(aSubject, FLAVOR_HTML);
- } else {
- message.body = item.description;
- }
- break;
-
- case FLAVOR_FLOCK_MEDIA:
- case FLAVOR_MOZ_URL:
- contentParts = content.split("\n");
- message.subject = contentParts[1];
- message.body = contentParts[0];
- break;
-
- case FLAVOR_TEXT_CITE:
- contentParts = content.split("\n");
- message.subject = contentParts[2];
- message.body = content;
- break;
-
- case FLAVOR_HTML_CITE:
- message.subject = "";
- message.body = content;
- break;
-
- case FLAVOR_UNICODE:
- contentParts = content.split(": ");
- // Can parse if the ": " separator doesn't occur more than once
- if (contentParts.length == 2) {
- message.subject = contentParts[0];
- message.body = contentParts[1];
- } else {
- message.subject = "";
- message.body = content;
- }
- break;
-
- case FLAVOR_HTML:
- message.subject = "";
- message.body = content;
- break;
- }
-
- if (!message.body) {
- _logger.debug("The flavor '"+aFlavor+"' is unsupported by this method");
- }
-
- return message;
- }
-
- // Used code from viewPartialSource.js
- flockRichDragDropService.prototype._selectionToHtml =
- function fRDDS__selectionToHtml(aSelection) {
- var inst = this;
-
- /////////////////////////////////////////////////////////////////////////
- // helper to get a path like FIXptr, but with an array
- // instead of the "tumbler" notation
- // see FIXptr:
- // http://lists.w3.org/Archives/Public/www-xml-linking-comments/2001AprJun/att-0074/01-NOTE-FIXptr-20010425.htm
- function getPath(ancestor, node) {
- var n = node;
- var p = n.parentNode;
- if (n == ancestor || !p) {
- return null;
- }
- var path = [];
- if (!path) {
- return null;
- }
- do {
- for (var i = 0; i < p.childNodes.length; i++) {
- if (p.childNodes.item(i) == n) {
- path.push(i);
- break;
- }
- }
- n = p;
- p = n.parentNode;
- } while (n != ancestor && p);
- return path;
- };
-
- function makeRelativeLinksAbsolute(aBaseUrl, aDOMNode) {
- // This is a recursive method: bail if no tag name
- if (!aDOMNode.tagName) {
- return;
- }
-
- switch (aDOMNode.tagName.toLowerCase()) {
- case "img":
- var url = aDOMNode.getAttribute("src");
- if (!url.match("http")) {
- aDOMNode.setAttribute("src", inst._makeURLAbsolute(aBaseUrl, url));
- }
- break;
-
- case "a":
- var url = aDOMNode.getAttribute("href");
- if (url && !url.match("http")) {
- aDOMNode.setAttribute("href", inst._makeURLAbsolute(aBaseUrl, url));
- }
- break;
-
- default:
- break
- }
- if (aDOMNode.hasChildNodes()) {
- var kids = aDOMNode.childNodes;
- for (var i = 0; i < kids.length; i++) {
- makeRelativeLinksAbsolute(aBaseUrl, kids[i]);
- }
- }
- };
-
- var range = aSelection.getRangeAt(0);
- var ancestorContainer = range.commonAncestorContainer;
- var doc = ancestorContainer.ownerDocument;
-
- var startContainer = range.startContainer;
- var endContainer = range.endContainer;
- var startOffset = range.startOffset;
- var endOffset = range.endOffset;
-
- // let the ancestor be an element
- if (ancestorContainer.nodeType == CI.nsIDOMNode.TEXT_NODE ||
- ancestorContainer.nodeType == CI.nsIDOMNode.CDATA_SECTION_NODE)
- {
- ancestorContainer = ancestorContainer.parentNode;
- }
-
- // for selectAll, let's use the entire document, including <html>...</html>
- // @see DocumentViewerImpl::SelectAll() for how selectAll is implemented
- try {
- if (ancestorContainer == doc.body) {
- ancestorContainer = doc.documentElement;
- }
- } catch (ex) {
- }
-
- // each path is a "child sequence" (a.k.a. "tumbler") that
- // descends from the ancestor down to the boundary point
- var startPath = getPath(ancestorContainer, startContainer);
- var endPath = getPath(ancestorContainer, endContainer);
-
- // clone the fragment of interest and reset everything to be relative to it
- // note: it is with the clone that we operate from now on
- ancestorContainer = ancestorContainer.cloneNode(true);
- startContainer = ancestorContainer;
- endContainer = ancestorContainer;
- var i;
- for (i = startPath ? startPath.length-1 : -1; i >= 0; i--) {
- startContainer = startContainer.childNodes.item(startPath[i]);
- }
- for (i = endPath ? endPath.length-1 : -1; i >= 0; i--) {
- endContainer = endContainer.childNodes.item(endPath[i]);
- }
-
- // add special markers to record the extent of the selection
- // note: |startOffset| and |endOffset| are interpreted either as
- // offsets in the text data or as child indices (see the Range spec)
- // (here, munging the end point first to keep the start point safe...)
- var tmpNode;
- if (endContainer.nodeType == CI.nsIDOMNode.TEXT_NODE ||
- endContainer.nodeType == CI.nsIDOMNode.CDATA_SECTION_NODE)
- {
- // do some extra tweaks to try to avoid the view-source output to look like
- // ...<tag>]... or ...]</tag>... (where ']' marks the end of selection).
- // To get a neat output, the idea here is to remap the end point from:
- // 1. ...<tag>]... to ...]<tag>...
- // 2. ...]</tag>... to ...</tag>]...
- if ((endOffset > 0 && endOffset < endContainer.data.length) ||
- !endContainer.parentNode ||
- !endContainer.parentNode.parentNode)
- {
- endContainer.insertData(endOffset, MARK_SELECTION_END);
- } else {
- tmpNode = doc.createTextNode(MARK_SELECTION_END);
- endContainer = endContainer.parentNode;
- if (endOffset == 0) {
- endContainer.parentNode.insertBefore(tmpNode, endContainer);
- } else {
- endContainer.parentNode.insertBefore(tmpNode, endContainer.nextSibling);
- }
- }
- } else {
- tmpNode = doc.createTextNode(MARK_SELECTION_END);
- endContainer.insertBefore(tmpNode, endContainer.childNodes.item(endOffset));
- }
-
- if (startContainer.nodeType == CI.nsIDOMNode.TEXT_NODE ||
- startContainer.nodeType == CI.nsIDOMNode.CDATA_SECTION_NODE)
- {
- // do some extra tweaks to try to avoid the view-source output to look like
- // ...<tag>[... or ...[</tag>... (where '[' marks the start of selection).
- // To get a neat output, the idea here is to remap the start point from:
- // 1. ...<tag>[... to ...[<tag>...
- // 2. ...[</tag>... to ...</tag>[...
- if ((startOffset > 0 && startOffset < startContainer.data.length) ||
- !startContainer.parentNode ||
- !startContainer.parentNode.parentNode ||
- startContainer != startContainer.parentNode.lastChild)
- {
- startContainer.insertData(startOffset, MARK_SELECTION_START);
- } else {
- tmpNode = doc.createTextNode(MARK_SELECTION_START);
- startContainer = startContainer.parentNode;
- if (startOffset == 0) {
- startContainer.parentNode.insertBefore(tmpNode, startContainer);
- } else {
- startContainer.parentNode.insertBefore(tmpNode,
- startContainer.nextSibling);
- }
- }
- } else {
- tmpNode = doc.createTextNode(MARK_SELECTION_START);
- startContainer.insertBefore(tmpNode,
- startContainer.childNodes.item(startOffset));
- }
-
- // now extract, make url absolute and return the HTML source
- tmpNode = doc.createElementNS(NS_XHTML, "div");
- tmpNode.appendChild(ancestorContainer);
- makeRelativeLinksAbsolute(doc.location, tmpNode);
-
- return tmpNode.innerHTML;
- }
-
-
- flockRichDragDropService.prototype._makeURLAbsolute =
- function fRDDS__makeURLAbsolute(aBase, aUrl) {
- try {
- var ioService = CC["@mozilla.org/network/io-service;1"]
- .getService(CI.nsIIOService);
- var baseURI = ioService.newURI(aBase, null, null);
-
- return ioService.newURI(baseURI.resolve(aUrl), null, null).spec;
- } catch (ex) {
- // Special URLs throw exceptions, in this case we just return it "as is"
- return aUrl;
- }
- }
-
-
- flockRichDragDropService.prototype._makeHTMLCitation =
- function fRDDS__makeHTMLCitation(aUrl, aTitle, aContent) {
- var source = <p class="citation">
- <cite>
- <a href={aUrl}>{aTitle}</a>
- </cite>
- </p>;
-
- // We don't use E4X here because it would escape "aContent"
- var result = "<blockquote cite=" + aUrl + ">"
- + "<p>" + aContent + "</p>"
- + "</blockquote>"
- + source.toXMLString();
-
- return result;
- }
-
-
- flockRichDragDropService.prototype._makeTextCitation =
- function fRDDS__makeTextCitation(aUrl, aTitle, aContent) {
- var result = aContent + "\n\n"
- + aTitle + "\n"
- + aUrl;
-
- return result;
- }
-
-
- flockRichDragDropService.prototype._addTextFlavour =
- function fRDDS__addTextFlavour(aTransferable,
- aFlavour,
- aTextData)
- {
- var supports = CC["@mozilla.org/supports-string;1"]
- .createInstance(CI.nsISupportsString);
- supports.data = aTextData;
- aTransferable.addDataFlavor(aFlavour);
- var length = supports.data.length * 2;
- aTransferable.setTransferData(aFlavour, supports, length);
-
- return aTransferable;
- }
-
-
- flockRichDragDropService.prototype._getImageTransferable =
- function fRDDS__getImageTransferable(aImageUrl,
- aImageTitle,
- aWebPageUrl)
- {
- var result = CC["@mozilla.org/widget/transferable;1"]
- .createInstance(CI.nsITransferable);
-
- // text/x-moz-url
- var urltext = ((aImageTitle.length) ? (aImageTitle + ":\n") : "")
- + aWebPageUrl;
- this._addTextFlavour(result, FLAVOR_MOZ_URL, urltext);
-
- // text/x-flock-media
- var text = aImageUrl + "\n" + aImageTitle;
- this._addTextFlavour(result, FLAVOR_FLOCK_MEDIA, text);
-
- // text/unicode
- var text = ((aImageTitle.length) ? (aImageTitle + ": ") : "")
- + aImageUrl;
- this._addTextFlavour(result, FLAVOR_UNICODE, text);
-
- // text/html
- var html = <a href={aWebPageUrl} title={aImageTitle}>
- <img alt={aImageTitle} src={aImageUrl}/>
- </a>;
- this._addTextFlavour(result, FLAVOR_HTML, html.toXMLString());
-
- // text/x-flock-htmlcitation
- var citation = this._makeHTMLCitation(aWebPageUrl, aImageTitle, html);
- this._addTextFlavour(result, FLAVOR_HTML_CITE, citation);
-
- return result;
- }
-
-
- flockRichDragDropService.prototype._getLinkTransferable =
- function fRDDS__getLinkTransferable(aURL, aTitle) {
- var result = CC["@mozilla.org/widget/transferable;1"]
- .createInstance(CI.nsITransferable);
- // text/x-moz-url
- var urltext = aURL + "\n" + aTitle;
- this._addTextFlavour(result, FLAVOR_MOZ_URL, urltext);
-
- // text/unicode
- var text = aTitle + ": " + aURL;
- this._addTextFlavour(result, FLAVOR_UNICODE, text);
-
- // text/html
- var html = <a href={aURL}>{aTitle}</a>;
- this._addTextFlavour(result, FLAVOR_HTML, html.toXMLString());
-
- return result;
- }
-
-
- flockRichDragDropService.prototype._getSelectionTransferable =
- function fRDDS__getSelectionTransferable(aURL, aTitle, aSelection) {
- var result = CC["@mozilla.org/widget/transferable;1"]
- .createInstance(CI.nsITransferable);
-
- // text/x-flock-htmlcitation
- var htmlCitation = this._makeHTMLCitation(aURL, aTitle, html)
- this._addTextFlavour(result, FLAVOR_HTML_CITE, htmlCitation);
-
- // text/x-flock-textcitation
- var textCitation = this._makeTextCitation(aURL, aTitle, text)
- this._addTextFlavour(result, FLAVOR_TEXT_CITE, textCitation);
-
- // text/unicode
- var text = aTitle + ": " + aSelection.toString();
- this._addTextFlavour(result, FLAVOR_UNICODE, text);
-
- // text/html
- var html = this._selectionToHtml(aSelection);
- this._addTextFlavour(result, FLAVOR_HTML, html);
-
- return result;
- }
-
-
- flockRichDragDropService.prototype._getMediabarTransferable =
- function fRDDS__getMediabarTransferable(aMedia, aTopUrl)
- {
- var result = CC["@mozilla.org/widget/transferable;1"]
- .createInstance(CI.nsITransferable);
-
- var title = aMedia.title.replace(/%20/g, " ");
- var url = aMedia.webPageUrl;
- var imageUrl = aMedia.midSizePhoto;
-
- // text/x-moz-url
- var urltext = ((title.length) ? (title + ":\n") : "") + aTopUrl;
- this._addTextFlavour(result, FLAVOR_MOZ_URL, urltext);
-
- // text/x-flock-media
- var text = url + "\n" + title;
- this._addTextFlavour(result, FLAVOR_FLOCK_MEDIA, text);
-
- // text/unicode
- var text = ((title.length) ? (title + ": ") : "") + url;
- this._addTextFlavour(result, FLAVOR_UNICODE, text);
-
- // text/html
- var html;
- if (eval(aMedia.is_video)) {
- // video
- html = aMedia.buildHTML();
- this._addTextFlavour(result, FLAVOR_HTML, html);
- } else {
- // photo
- html = <a href={url} title={title}>
- <img alt={title} src={imageUrl}/>
- </a>;
- this._addTextFlavour(result, FLAVOR_HTML, html.toXMLString());
- }
-
- // text/x-flock-htmlcitation
- var citation = this._makeHTMLCitation(aTopUrl, title, html);
- this._addTextFlavour(result, FLAVOR_HTML_CITE, citation);
-
- return result;
- }
-
-
- // Retrieves the flavour data from the transferable
- flockRichDragDropService.prototype._getFlavourData =
- function fRDDS__getFlavourData(aTransferable, aFlavor) {
- if (!aTransferable || !aFlavor) {
- return "";
- }
-
- var dataObj = {};
- var len = {};
-
- // If the flavor is not in the transferable, then this call will throw
- try {
- aTransferable.getTransferData(aFlavor, dataObj, len);
- } catch (ex) {
- _logger.debug("The flavor '"+aFlavor+"' is unsupported by this transferable");
- return "";
- }
-
- return dataObj.value.QueryInterface(CI.nsISupportsString).data;
- }
-
-
- // Determine the appropriate action when dropping rich content onto a TEXTAREA
- // element.
- flockRichDragDropService.prototype._handleDropToTextArea =
- function frDDS__handleDropToTextArea(aSession, aTextarea) {
- if (!(aSession && aTextarea)) {
- return false;
- }
-
- var catMgr = CC[FLOCK_CATEGORY_MANAGER_CONTRACT_ID]
- .getService(CI.nsICategoryManager);
- var svcEnum = catMgr.enumerateCategory(FLOCK_RICH_CONTENT_CATEGORY_ENTRY);
- if (!svcEnum) {
- return false;
- }
-
- // Get the various rich content flavours
- var trans = this.getRichSelection(aSession);
-
- // Find the appropriate supported service to drop the rich content on
- while (svcEnum.hasMoreElements()) {
- var entry = svcEnum.getNext().QueryInterface(CI.nsISupportsCString);
- if (entry) {
- var contractID = catMgr.getCategoryEntry(FLOCK_RICH_CONTENT_CATEGORY_ENTRY,
- entry.data);
- var service = CC[contractID].getService(CI.flockIRichContentDropHandler);
- if (service.handleDrop(trans, aTextarea)) {
- // Dropped the rich content on the appropriate supported service,
- // no need to continue searching
- return true;
- }
- }
- }
-
- // Could not find the appropriate supported service to drop the rich
- // context on, drop uber-flav
- var uberFlavour = this._getUberFlavour(trans);
- if (uberFlavour) {
- this._addToTextarea(uberFlavour, aTextarea);
- return true;
- }
-
- // No uber-flavour either
- return false;
- }
-
-
- // Determine the appropriate action when dropping rich content onto an element
- // within a rich text editor
- flockRichDragDropService.prototype._handleDropToRichTextEditor =
- function frDDS__handleDropToRichTextEditor(aSession, aTargetElement) {
- if (!(aSession && aTargetElement)) {
- return false;
- }
-
- // Get the various rich content flavours
- var transferable = this.getRichSelection(aSession);
- if (!transferable) {
- return false;
- }
-
- // Get rich content
- var content = this._getFlavourData(transferable, FLAVOR_HTML);
- if (!content || this._isRichVideoContent(content)) {
- // If we couldn't get the rich content or it's a video, just get plain text
- // "Rich textareas" used in mail clients cannot accept HTML OBJECT or
- // EMBED tags
- content = this._getFlavourData(transferable, FLAVOR_UNICODE);
- content = content.replace(/: /g, ":<br />");
- }
-
- // Add it to the editor
- if (content) {
- this._addToRichTextEditor(content, aTargetElement);
- return true;
- }
-
- // We have failed
- return false;
- }
-
-
- // Check if the content is rich video content
- flockRichDragDropService.prototype._isRichVideoContent =
- function fRDDS__isRichVideoContent(aContent) {
- // Rich video content will be made up of:
- // 1) an EMBED tag or
- // 2) an EMBED tag within an OBJECT tag
- return aContent && (aContent.toLowerCase().indexOf("<embed ") > -1);
- }
-
-
- // Get the uber flavour with the desired richness
- flockRichDragDropService.prototype._getUberFlavour =
- function fRDDS__getUberFlavour(aTransferable, aType) {
- if (!aTransferable) {
- return "";
- }
-
- var uberFlavour = "";
-
- var newline = "\n";
- if (aType == "rich") {
- newline = "<br />";
- }
-
- var link = this._getFlavourData(aTransferable, FLAVOR_UNICODE);
- if (link) {
- uberFlavour = flockGetString("common/sharing",
- "flock.sharing.uberFlavour.link")
- + newline + link;
- }
-
- var content = this._getFlavourData(aTransferable, FLAVOR_HTML);
- if (content) {
- if (uberFlavour) {
- uberFlavour += newline + newline;
- }
-
- uberFlavour += flockGetString("common/sharing",
- "flock.sharing.uberFlavour.content")
- + newline + this._sanitizeHTMLContent(content);
- }
-
- return uberFlavour;
- }
-
-
- flockRichDragDropService.prototype._sanitizeHTMLContent =
- function fRDDS__sanitizeHTMLContent(aContent) {
- return aContent.replace(/&/g, "&");
- }
-
-
- flockRichDragDropService.prototype._isInRichTextEditor =
- function fRDDS__isInRichTextEditor(aElement) {
- return aElement.ownerDocument.designMode == "on";
- }
-
-
- // Add the content to the text area object
- flockRichDragDropService.prototype._addToTextarea =
- function fRDDS__addToTextArea(aContent, aTextarea) {
- if (aContent && aTextarea) {
- var caretPos = aTextarea.selectionEnd;
- var currentValue = aTextarea.value;
- var breadcrumb = (aTextarea.value.length == caretPos)
- ? this.getBreadcrumb()
- : "";
- aTextarea.value = currentValue.substring(0, caretPos)
- + aContent
- + currentValue.substring(caretPos)
- + breadcrumb;
- }
- }
-
-
- // Add the content to the targeted elment in the rich text editor
- flockRichDragDropService.prototype._addToRichTextEditor =
- function fRDDS__addToRichTextEditor(aContent, aTargetElement) {
- if (aContent && aTargetElement) {
- var doc = aTargetElement.ownerDocument;
- var targetName = aTargetElement.localName.toLowerCase();
-
- // Create SPAN element containing content
- var contentElement = doc.createElement("span");
- contentElement.innerHTML = aContent;
-
- if (targetName == "html" || targetName == "body") {
- // Not any specific element within the body, so add at insertion point
- doc.execCommand("insertHTML", false, aContent);
- } else {
- // Insert after target element
- aTargetElement.parentNode.insertBefore(contentElement,
- aTargetElement.nextSibling);
- }
-
- // Check for breadcrumb -- we don't want to add more than one
- if (!doc.getElementById(FLOCK_BREADCRUMB_ID)) {
- // Append the breadcrumb to the body
- var breadcrumbElement = doc.createElement("span");
- breadcrumbElement.setAttribute("id", FLOCK_BREADCRUMB_ID);
- breadcrumbElement.innerHTML = this.getBreadcrumb("rich");
- doc.body.appendChild(breadcrumbElement);
- }
- }
- }
-
- /**************************************************************************
- * END Flock Rich Drag Drop Service Private Members
- **************************************************************************/
-
- /**************************************************************************
- * END Flock Rich Drag Drop Service
- **************************************************************************/
-
- /**************************************************************************
- * Helper Components
- **************************************************************************/
-
- const JS_SUBSCRIPT_LOADER_CONTRACTID = "@mozilla.org/moz/jssubscript-loader;1";
-
- function loadSubScript(spec) {
- var loader = CC[JS_SUBSCRIPT_LOADER_CONTRACTID]
- .getService(CI.mozIJSSubScriptLoader);
- var context = {};
- loader.loadSubScript(spec, context);
- return context;
- }
-
- function loadLibraryFromSpec(aSpec) {
- var loader = CC[JS_SUBSCRIPT_LOADER_CONTRACTID]
- .getService(CI.mozIJSSubScriptLoader);
- loader.loadSubScript(aSpec);
- }
-
- loadLibraryFromSpec("chrome://flock/content/common/flocksafe.js");
-
- /**************************************************************************
- * XPCOM Support - Module Construction
- **************************************************************************/
-
- // Create array of components.
- var componentArray = [flockRichDragDropService];
-
- // Wrap the components in a module.
- var module = new FlockXPCOMUtils.genericModule(MODULE_NAME, componentArray);
-
- // Provide XPCOM with access to the module.
- function NSGetModule(aCompMgr, aFileSpec) {
- return module;
- }
-
- /**************************************************************************
- * END XPCOM Support
- **************************************************************************/
-